package jflowmap.model.ontology;

import java.util.Set;

import com.google.common.base.Predicate;
import com.google.common.collect.Sets;

public class Filters {

	public static Filter oneDimensionIsDirectChildOf(Context context, String dimensionName) {
		return new OneDimensionIsDirectChildOf(context.getDimension(dimensionName));
	}
	public static Filter oneDimensionIsDeepChildOf(Context context, String dimensionName) {
		return new OneDimensionIsDeepChildOf(context.getDimension(dimensionName));
	}
	public static Filter oneDimensionIsDirectPartOf(Context context, String dimensionName) {
		return new OneDimensionIsDirectPartOf(context.getDimension(dimensionName));
	}
	public static Filter oneDimensionIsDeepPartOf(Context context, String dimensionName) {
		return new OneDimensionIsDeepPartOf(context.getDimension(dimensionName));
	}
	public static Filter hasDimension(Context context, String dimensionName) {
		return new HasDimension(context.getDimension(dimensionName));
	}
	public static Filter matching(Match match) {
		return new MatchingFilter(match);
	}
	
	public static class MatchingFilter extends Filter {
		final Match match;
		public MatchingFilter (Match match) {
			this.match = match;
		}
		
		@Override
		public Set<Value> reduce(Set<Value> values) {
			return Sets.filter(values, new Predicate<Value>() {
				@Override
				public boolean apply(Value value) {
					if (match.matches(value)) return true;
					return false;
				}
			});
		}
	}
	
	public static class OneDimensionIsDirectChildOf extends Filter {
		final Dimension parent;
		public OneDimensionIsDirectChildOf(Dimension parent) {
			this.parent = parent;
		}		
		
		@Override
		public Set<Value> reduce(Set<Value> values) {
			return Sets.filter(values, new Predicate<Value>() {
				@Override
				public boolean apply(Value value) {
					if (value.isDirectChildOf(parent)) return true;
					else return false;
				}
				
			});
		}
	}
	
	public static class OneDimensionIsDeepChildOf extends Filter {
		final Dimension parent;
		public OneDimensionIsDeepChildOf(Dimension parent) {
			this.parent = parent;
		}

		@Override
		public Set<Value> reduce(Set<Value> values) {
			return Sets.filter(values, new Predicate<Value>() {
				@Override
				public boolean apply(Value value) {
					if (value.isDeepChildOf(parent)) return true;
					return false;
				}
				
			});
		}
	}
	
	public static class OneDimensionIsDirectPartOf extends Filter {
		final Dimension parent;
		public OneDimensionIsDirectPartOf(Dimension parent) {
			this.parent = parent;
		}		
		
		@Override
		public Set<Value> reduce(Set<Value> values) {
			return Sets.filter(values, new Predicate<Value>() {
				@Override
				public boolean apply(Value value) {
					if (value.isDirectPartOf(parent)) return true;
					else return false;
				}
				
			});
		}
	}
	
	public static class OneDimensionIsDeepPartOf extends Filter {
		final Dimension parent;
		public OneDimensionIsDeepPartOf(Dimension parent) {
			this.parent = parent;
		}

		@Override
		public Set<Value> reduce(Set<Value> values) {
			return Sets.filter(values, new Predicate<Value>() {
				@Override
				public boolean apply(Value value) {
					if (value.isDeepPartOf(parent)) return true;
					return false;
				}
				
			});
		}
	}
	
	public static class HasDimension extends Filter {
		final Dimension parent;
		public HasDimension(Dimension parent) {
			this.parent = parent;
		}

		@Override
		public Set<Value> reduce(Set<Value> values) {
			return Sets.filter(values, new Predicate<Value>() {
				@Override
				public boolean apply(Value value) {
					if (value.is(parent)) return true;
					return false;
				}
				
			});
		}
	}
}
